use actix_cors::Cors;
use actix_web::{App, HttpServer};
use actix_web::middleware::Logger;
use actix_web::web::Data;
use dotenv::dotenv;
use local_ip_address::local_ip;
use utoipa::OpenApi;
use utoipa_swagger_ui::SwaggerUi;
use crate::base::Config;
use crate::router::{create_router, ApiDoc};

mod handler;
mod middleware;
mod router;
mod service;
mod base;
mod data;
mod repository;

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    // 加载环境配置
    dotenv().ok();
    env_logger::init();

    // 加载自定义配置
    let config = Config::from_env().expect("加载环境配置文件失败");

    // 创建数据库连接池
    let db_pool = config.create_db_pool().await.expect("创建数据库连接池失败");

    // 创建OpenAPI文档对象
    let openapi = ApiDoc::openapi();

    // 先拷贝 host 和 port，避免 move
    let host = config.host.clone();
    let port = config.port;

    // 获取本机的实际地址
    let local_ip = local_ip().unwrap_or_else(|_| host.parse().unwrap_or("127.0.0.1".parse().unwrap()));
    let uri = format!("http://{}:{}", local_ip, port);

    log::info!("🚀 服务启动: {}", uri);
    log::info!("📚 Swagger UI: {}/swagger-ui/", uri);
    log::info!("📄 OpenAPI 文档: {}/api-docs/openapi.json", uri);

    HttpServer::new(move || {
        // 配置 CORS 跨域策略
        let cors = Cors::default()
            .allow_any_origin()
            .allowed_methods(vec!["GET", "POST", "PUT", "DELETE"])
            .allowed_headers(vec![
                actix_web::http::header::AUTHORIZATION,
                actix_web::http::header::ACCEPT,
                actix_web::http::header::CONTENT_TYPE
            ])
            .supports_credentials()
            .max_age(3600);

        App::new()
            .app_data(Data::new(db_pool.clone())) // 注入数据库连接池
            .app_data(Data::new(config.clone())) // 注入全局配置
            .app_data(Logger::default()) // 注入日志
            .wrap(cors)
            .service(
                SwaggerUi::new("/swagger-ui/{_:.*}")
                    .url("/api-docs/openapi.json", openapi.clone())
            )
            .configure(create_router)

    })
    .bind((host, port))?
    .run()
    .await
}